/*
 * Copyright (c) 2010, Jan Pastor. All Rights Reserved.
 */

package sk.jp.jitag.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import java.util.List;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sk.jp.commons.ui.ExceptionDialog;
import sk.jp.commons.ui.InfoDialog;
import sk.jp.commons.ui.LeaveGridLayout;
import sk.jp.commons.utils.LogMsg;
import sk.jp.jitag.model.config.FileFormat;
import sk.jp.jitag.model.config.Profile;
import sk.jp.jitag.model.config.Tool;
import sk.jp.jitag.ui.common.IconLoader;
import sk.jp.jitag.ui.common.Icons;
import sk.jp.jitag.util.Msg;

/**
 * Assign file format with tools dialog.
 */
public class FormatToolsDialog extends JDialog implements ActionListener {

    private static final Logger log = LoggerFactory.getLogger(FormatToolsDialog.class);

    private enum ActionCode {
        save,
        cancel,
        formatSelected,
        assignTool,
        addTool,
        removeTool,
        editTool,
        moveUpAsignedTool,
        moveDownAsignedTool,
        unasigneTool,
        ;
    }

    private Profile profile;

    private JComboBox formatsComboBox = null;
    private JTextField formatDesc = null;
    private JList allToolsList = null;
    private JList selectedToolsList = null;
    private JButton btnOk = null;

    //----------------------------------------------------------------------

    /**
     * Initialize dialog.
     * @param ownerDialog
     * @param profile
     */
    public FormatToolsDialog(JDialog ownerDialog, Profile profile) {
        super(ownerDialog, Msg.ftoolsDialogTitle.value(), true);

        this.profile = profile;
    }

    //----------------------------------------------------------------------

    /**
     * Opens dialog with current configuration profile values. Changes are
     * reflected to current profile immediately.
     */
    public void open(){
        init();

        pack();
        btnOk.requestFocusInWindow();

        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension screenDimension = toolkit.getScreenSize();
        Dimension size = getSize();
        setLocation((screenDimension.width - size.width) / 2,
                    (screenDimension.height - size.height) / 2);

        setVisible(true);
    }

    //----------------------------------------------------------------------

    @Override
    public void setVisible(boolean visible) {
        if(!visible){
            //on close
            actionCancel();
        }
        super.setVisible(visible);
    }

    private void init(){
        Container contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());

        LeaveGridLayout leaveGridLayout;

        //Format Panel

        leaveGridLayout = new LeaveGridLayout(2, 2, 4, 5,
                                              LeaveGridLayout.HAlign.left,
                                              LeaveGridLayout.VAlign.top);
        leaveGridLayout.setColumnsHAlign(LeaveGridLayout.HAlign.right,
                                         LeaveGridLayout.HAlign.left);
        JPanel formatPanel = new JPanel(leaveGridLayout);
        formatPanel.setBorder(BorderFactory.createEmptyBorder(6, 4, 6, 4));
        contentPane.add(formatPanel, BorderLayout.PAGE_START);

        formatPanel.add(new JLabel(Msg.ftoolsDialogFileFormat.value())); //File format:
        formatsComboBox = new JComboBox(new Vector<FileFormat>(profile.getFileFormats()));
        formatPanel.add(formatsComboBox);
        formatsComboBox.addActionListener(this);
        formatsComboBox.setActionCommand(ActionCode.formatSelected.name());
        formatsComboBox.setRenderer(new BasicComboBoxRenderer(){
            @Override
            public Component getListCellRendererComponent(JList list, Object value, int index,
                                                          boolean isSelected, boolean cellHasFocus) {
                BasicComboBoxRenderer c;
                c = (BasicComboBoxRenderer) super.getListCellRendererComponent(
                                                        list, value, index,
                                                        isSelected, cellHasFocus);
                if(value != null){
                    c.setText(((FileFormat)value).getLabel());
                }
                return c;
            }
        });

        formatPanel.add(new JLabel(" "));
        formatDesc = new JTextField("", 25);
        formatPanel.add(formatDesc);
        formatDesc.setEditable(false);

        //Tools Panel

        leaveGridLayout = new LeaveGridLayout(5, 2, 4, 5,
                                                LeaveGridLayout.HAlign.left,
                                                LeaveGridLayout.VAlign.top);
        JPanel mainPanel = new JPanel(leaveGridLayout);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(6, 4, 6, 4));
        contentPane.add(mainPanel, BorderLayout.CENTER);

        // //
        mainPanel.add(new JLabel(Msg.ftoolsDialogAllTools.value()));//All tools:
        mainPanel.add(new JLabel(" "));
        mainPanel.add(new JLabel(" "));
        mainPanel.add(new JLabel(Msg.ftoolsDialogSelTools.value()));//Selected tools:
        mainPanel.add(new JLabel(" "));

        // //
        DefaultListCellRenderer toolCellRenderer = new DefaultListCellRenderer(){
                @Override
                public Component getListCellRendererComponent(JList list, Object value, int index,
                                                              boolean isSelected, boolean cellHasFocus) {
                    Tool _tool = (Tool) value;
                    DefaultListCellRenderer c;
                    c = (DefaultListCellRenderer) super.getListCellRendererComponent(
                                        list, value, index, isSelected, cellHasFocus);
                    c.setText(_tool.getLabel());
                    return c;
                }
            };
        DefaultListModel listModel;

        listModel = new DefaultListModel();
        for (Tool tool : profile.getTools()) {
            listModel.addElement(tool);
        }
        allToolsList = new JList(listModel);
        allToolsList.setVisibleRowCount(8);
        allToolsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        allToolsList.setCellRenderer(toolCellRenderer);

        JScrollPane scrollPane = new JScrollPane(allToolsList,
                                                 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                                                 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setPreferredSize(new Dimension(164, 128));
        mainPanel.add(scrollPane);

        LeaveGridLayout lgl;
        lgl = new LeaveGridLayout(1, 6);
        JPanel panel = new JPanel(lgl);
        mainPanel.add(panel);
        panel.add(createImgButton(Icons.arrowNext, ActionCode.assignTool));
        panel.add(createImgButton(Icons.arrowPrevious, ActionCode.unasigneTool));
        panel.add(new JLabel(" "));
        panel.add(createImgButton(Icons.add, ActionCode.addTool));
        panel.add(createImgButton(Icons.remove, ActionCode.removeTool));
        panel.add(createImgButton(Icons.editPaper, ActionCode.editTool));
        mainPanel.add(new JLabel(" "));

        //

        selectedToolsList = new JList(new DefaultListModel());
        selectedToolsList.setVisibleRowCount(8);
        selectedToolsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        selectedToolsList.setCellRenderer(toolCellRenderer);

        scrollPane = new JScrollPane(selectedToolsList,
                                                 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                                                 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setPreferredSize(new Dimension(164, 128));
        mainPanel.add(scrollPane);

        lgl = new LeaveGridLayout(1, 2);
        panel = new JPanel(lgl);
        mainPanel.add(panel);
        panel.add(createImgButton(Icons.arrowUp, ActionCode.moveUpAsignedTool));
        panel.add(createImgButton(Icons.arrowDown, ActionCode.moveDownAsignedTool));

        //Buttons
        
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        contentPane.add(buttonPanel, BorderLayout.PAGE_END);

        //
        btnOk = createButton(Msg.commonOk, ActionCode.save); //OK
        buttonPanel.add(btnOk);
//        buttonPanel.add(createButton(Msg.commonCancel, ActionCode.cancel));  //Cancel

        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

        //

        if(profile.getFileFormats().size() > 0){
            formatsComboBox.setSelectedIndex(0);
        }                
    }

    private JButton createButton(Msg btnLabel, ActionCode actionCode){
        JButton button = new JButton(btnLabel.value());
        button.setActionCommand(actionCode.name());
        button.addActionListener(this);
        return button;
    }

    private JButton createImgButton(Icons icon, ActionCode actionCode){
        ImageIcon imageIcon = IconLoader.loadIcon(icon);
        JButton button = new JButton(imageIcon);
        button.setPreferredSize(new Dimension(imageIcon.getIconWidth()+4,
                                              imageIcon.getIconHeight()+4));
        button.setActionCommand(actionCode.name());
        button.addActionListener(this);
        return button;
    }

    public void actionPerformed(ActionEvent event) {
        try {
            processAction(ActionCode.valueOf(event.getActionCommand()));
        }catch(Exception e){
            ExceptionDialog.show(this, e);
        }
    }

    @SuppressWarnings({"IfStatementWithTooManyBranches"})
    private void processAction(ActionCode actionCode){
        log.trace(LogMsg.inp("actionCode", actionCode));
        if(actionCode == ActionCode.cancel){
            actionCancel();
        }else if(actionCode == ActionCode.save){
            actionSave();
        }else if(actionCode == ActionCode.formatSelected){
            actionFormatSelected();
        }else if(actionCode == ActionCode.addTool){
            actionAddTool();
        }else if(actionCode == ActionCode.removeTool){
            actionRemoveTool();
        }else if(actionCode == ActionCode.editTool){
            actionEditTool();
        }else if(actionCode == ActionCode.assignTool){
            actionAssignTool();
        }else if(actionCode == ActionCode.moveUpAsignedTool){
            actionMoveUpAsignedTool();
        }else if(actionCode == ActionCode.moveDownAsignedTool){
            actionMoveDownAsignedTool();
        }else if(actionCode == ActionCode.unasigneTool){
            actionUnasigneTool();
        }else{
            new InfoDialog().show(this, "Not yet implemented");
        }
    }

    private void actionCancel(){
        dispose();
    }

    private void actionSave(){
        dispose();
    }

    private void actionFormatSelected(){
        FileFormat selectedFormat = (FileFormat) formatsComboBox.getSelectedItem();
        if(selectedFormat == null){
            return;
        }
        
        formatDesc.setText(selectedFormat.getDescription());

        DefaultListModel allToolsModel = (DefaultListModel) allToolsList.getModel();
        DefaultListModel assignedToolsModel = (DefaultListModel) selectedToolsList.getModel();
        //clear both lists
        allToolsModel.removeAllElements();
        assignedToolsModel.removeAllElements();

        //add all tools to all tools list
        List<Tool> allTools = profile.getTools();
        for (Tool tool : allTools) {
            allToolsModel.addElement(tool);
        }
        //add format tools to assigned tools list
        List<Tool> formatTools = selectedFormat.getTools();
        for (Tool formatTool : formatTools) {
            assignedToolsModel.addElement(formatTool);
        }
        //remove assigned tools from all tools list
        for (Tool tool : allTools) {
            if(assignedToolsModel.contains(tool)){
                allToolsModel.removeElement(tool);
            }
        }
    }

    private void actionAddTool(){
        ToolDialog toolDialog = new ToolDialog(this);
        toolDialog.open();
        Tool newTool = toolDialog.getTool();

        DefaultListModel listModel = (DefaultListModel) allToolsList.getModel();
        if(newTool != null && !listModel.contains(newTool.getLabel())){
            profile.addTool(newTool);
            listModel.addElement(newTool);
        }
    }

    private void actionRemoveTool(){
        Tool tool = (Tool) allToolsList.getSelectedValue();
        if(tool == null){
            return;
        }

        DefaultListModel listModel = (DefaultListModel) allToolsList.getModel();
        listModel.removeElement(tool);

        profile.getTools().remove(tool);
        List<FileFormat> formats = profile.getFileFormats();
        for (FileFormat format : formats) {
            format.getTools().remove(tool);
        }
    }

    private void actionEditTool(){
        Tool tool = (Tool) allToolsList.getSelectedValue();
        if(tool == null){
            return;
        }

        ToolDialog toolDialog = new ToolDialog(this, tool);
        toolDialog.open();
        Tool modifiedTool = toolDialog.getTool();
        if(modifiedTool != null){
            tool.setLabel(modifiedTool.getLabel());
            tool.setCmdLine(modifiedTool.getCmdLine());
        }
    }

    private void actionAssignTool(){
        FileFormat selectedFormat = (FileFormat) formatsComboBox.getSelectedItem();
        Tool selectedTool = (Tool) allToolsList.getSelectedValue();
        if(selectedFormat == null || selectedTool == null){
            return;
        }

        DefaultListModel selectedToolsListModel = (DefaultListModel) selectedToolsList.getModel();
        if(!selectedToolsListModel.contains(selectedTool)){
            selectedToolsListModel.addElement(selectedTool);
            ((DefaultListModel)allToolsList.getModel()).removeElement(selectedTool);
            selectedFormat.addTool(selectedTool);
        }
    }

    private void actionUnasigneTool(){
        FileFormat selectedFormat = (FileFormat) formatsComboBox.getSelectedItem();
        Tool assignedTool = (Tool) selectedToolsList.getSelectedValue();
        if(selectedFormat == null || assignedTool == null){
            return;
        }

        DefaultListModel assignedToolsModel = (DefaultListModel) selectedToolsList.getModel();
        DefaultListModel allToolsModel = (DefaultListModel) allToolsList.getModel();

        assignedToolsModel.removeElement(assignedTool);
        allToolsModel.addElement(assignedTool);
        selectedFormat.getTools().remove(assignedTool);
    }

    private void actionMoveUpAsignedTool(){
        moveTool(true);
    }

    private void actionMoveDownAsignedTool(){
        moveTool(false);
    }

    private void moveTool(boolean moveUp){
        FileFormat selectedFormat = (FileFormat) formatsComboBox.getSelectedItem();
        Tool assignedTool = (Tool) selectedToolsList.getSelectedValue();
        if(selectedFormat == null || assignedTool == null){
            return;
        }

        DefaultListModel assignedToolsModel = (DefaultListModel) selectedToolsList.getModel();
        int inx = assignedToolsModel.indexOf(assignedTool);
        if(moveUp && inx > 0){
            assignedToolsModel.remove(inx);
            assignedToolsModel.add(inx-1, assignedTool);
        }else if(!moveUp && inx < assignedToolsModel.size()-1){
            assignedToolsModel.remove(inx);
            assignedToolsModel.add(inx+1, assignedTool);
        }

        List<Tool> formatTools = selectedFormat.getTools();
        inx = formatTools.indexOf(assignedTool);
        if(inx == -1){
            //illegal state, remove tool from list
            assignedToolsModel.removeElement(assignedTool);
        }
        if(moveUp && inx > 0){
            formatTools.remove(inx);
            formatTools.add(inx-1, assignedTool);
        }else if(!moveUp && inx < formatTools.size()-1){
            formatTools.remove(inx);
            formatTools.add(inx+1, assignedTool);
        }
    }

}